/**
 * (C) 2005 - Boston University
 * 	Contact: Michael Ocean 

  This work is a part of the larger snBench project.  Information
  can be found at: http://csr.bu.edu/snbench

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**/
package step;

import java.util.ArrayList;


import step.Node;
import step.exceptions.IllegalChildException;
import step.exceptions.STEPException;

/**
 * A ConstNode allows its child to evaluate exactly
 * once.  Externally it will seem to be enabled but
 * only really executes its children once.
 *  
 * It blocks further evaluation by preventing passing
 * evaluated or wanted flags into its children after
 * its evaluated once
 * 
 * setWanted, ClearEvaluated, IsEnabled and
 * (of course) Evaluate() are overwritten
 * 
 * @author Michael
 *
 */
public class ConstNode extends Node
{
	/* keeps track of whether or not the 
	 * children have been evaluated */
	private boolean bEvaluatedOnce;
	
    public ConstNode() 
    {
    	super();
    	bEvaluatedOnce = false;
    }

    public ConstNode(String id)
    {
    	super(id);
    	bEvaluatedOnce = false;
    }
    
    /*
     * Get Value from children
     * 
     * @see step.Node#Evaluate()
     */
    public void Evaluate() throws EvaluationFailure 
    {   
		SetValue(GetInput(0));
		PushResult();

		bEvaluatedOnce = true;
    	rt_evaluated = true;
    }

    /* A ConstNode appears to be enabled if it's wanted,
     * not garbage and either:
     *  
     *  1) has not evaluated but has fresh input
     *  2) has evaluated and a parent wishes this node
     *    to run again (via ClearEvaluatedFlags)  
     * 
     * In the case of (2) the children will not be 
     * executed and instead a cached value will be returned
     * 
     * @see step.Node#IsEnabled()
     */
    public boolean IsEnabled() {
		if (!rt_wanted)
			return false;
		if(rt_garbage)
			return false;

		// if we haven't run yet, make sure we actually can
		if(!bEvaluatedOnce)
			return HasFreshInputs();
		
		// otherwise act just like a normal node
		return !rt_evaluated;
	}

    
    /* 
     * clearing the normal evaluated flag doesn't
     * effect us, but allows the caller to percieve
     * this node running at the correct times
     *  
     * @see step.Node#ClearEvaluatedFlags()
     */
    protected void ClearEvaluatedFlags()
    {
    	rt_evaluated = false;
		return;
    }

    /* SetWanted for a Const node is only active if the
     * node has never actually evaluated.  Otherwise
     * eat the wanted flag and prevent it from getting
     * to the children.
     * 
     * @see step.Node#SetWanted(boolean)
     */
    protected void SetWanted(boolean v) throws EvaluationFailure {  
	    rt_wanted = v;

	    /* need to check if the children have executed yet,
	     * if not, push down so the children can evaluate.
	     * Notice hasFreshInput protects for when child is a 
	     * splice node.
	     */
	    if((!bEvaluatedOnce)&&(!HasFreshInputs()))
		    for (int i=0 ; i<children.length ; i++) {
			    children[i].SetWanted(v);
		    }
    }
    
    public String TagName() { return "const"; }
    
    	// this code is added by ray

	//	 MODIFIES: compilationErrors 
	// EFFECT: checks if a Const Node has exavtly 1 child ( a Trigger node), if not it adds an exception to compilationErrors.

	public void validate(step.Graph g,
			ArrayList<STEPException> compilationErrors) {
		if (children.length < 1)
			compilationErrors
					.add(new IllegalChildException(
							"Node "
									+ this.GetID()
									+ " :Const node should have one child, this Const node doesn't have any"));
		else if (children.length > 1)
			compilationErrors
					.add(new IllegalChildException(
							"Node "
									+ this.GetID()
									+ " :Const node should have one child, this Const node have mora than one"));
		// const node paret should be trigger
		for (int i = 0; i < parents.length; i++) {
			if (!(parents[i].TagName().equals("trigger")
					|| parents[i].TagName().equals("edge_trigger") || parents[i]
					.TagName().equals("level_trigger")))
				compilationErrors
						.add(new IllegalChildException(
								"Node "
										+ this.GetID()
										+ " :Const node's Parent should be a kind of an treger"));
		}
	}

	@Override
	public Node ShallowCopy() {
		ConstNode cn = new ConstNode(this.ID);
		Node.CopyNonRTPropertiesFromAtoB(this,cn);
		return cn;
	}
}

